package Compiler;
import Data.Functions;

/**
 * this scanner of Compiler
 * 
 * @author Bing
 * 
 */
public class Scanner {

	/*
	 * the identifier code list
	 * 
	 * 0 unknown
	 * 
	 * reserved characters 1000 , 1001 ; 1002 ' 1003 . 1004 ( 1005 ) 1006 = 1007
	 * > 1008 < 1009 *
	 * 
	 * 1100 CREATE 1101 DATABASE 1102 TABLE 1103 INSERT 1104 DELETE 1105 INTO
	 * 1106 VALUES 1107 SET 1108 SELECT 1109 FROM 1110 WHERE 1111 AND 1112 OR
	 * 1113 NULL 1114 NOT 1115 ALL 1116 DISTINCT 1117 UNION 1118 AS 1119 ORDER
	 * 1120 BY 1121 GROUP 1122 USE
	 * 
	 * data type
	 * 1200 INTEGER 1201 REAL 1202 STRING
	 * 
	 * string list 2XXX XXX is the index in the string list
	 * 
	 * integer list 3XXX XXX is the index in the integer list
	 * 
	 * real list 4XXX XXX is the index in the real list
	 * 
	 * identifier list 5XXX XXX is the index in the identifier list
	 */

	public static int[] SCANNER_RESULT = null;
	public static String[] SCANNER_STRING_LIST = null;
	public static int[] SCANNER_INTEGER_LIST = null;
	public static double[] SCANNER_REAL_LIST = null;
	public static String[] SCANNER_IDENTIFIER_LIST = null;

	private static int str_index = 0;
	private static int rea_index = 0;
	private static int int_index = 0;
	private static int ide_index = 0;
	private static int res_index = 0;
	
	/**
	 * get values from the stack
	 * @param code the index
	 * @return String,double or int
	 */
	public static Object getValue(int code){
		switch(code/1000){
		case 2:
			return SCANNER_STRING_LIST[code-2000];
		case 3:
			return SCANNER_INTEGER_LIST[code-3000];
		case 4:
			return SCANNER_REAL_LIST[code-4000];
		case 5:
			return SCANNER_IDENTIFIER_LIST[code-5000];
		
		}
		
		return 0;
	}

	/**
	 * convert an input string to id code list
	 * 
	 * @param input
	 *            a string
	 * @return a integer array
	 */
	public static int[] scan(String input) {
		int p = 0; // pointer
		int size = input.length();
		SCANNER_RESULT = new int[size + 1];
		SCANNER_STRING_LIST = new String[size];
		SCANNER_INTEGER_LIST = new int[size];
		SCANNER_REAL_LIST = new double[size];
		SCANNER_IDENTIFIER_LIST = new String[size];

		str_index = 0;
		rea_index = 0;
		int_index = 0;
		ide_index = 0;
		res_index = 0;

		for (int i = 0; i < size + 1; i++)
			SCANNER_RESULT[i] = 0;

		String buff = "";

		while (p < size) {

			// read string '...'
			if (input.charAt(p) == '\'') {
				if (buff.length() != 0) {
					check(buff);
					buff = "";
				}
				p++;
				while (input.charAt(p) != '\'') {
					buff += input.charAt(p);
					p++;
					if (p == size) {
						perror();
						return null;
					}
				}

				SCANNER_STRING_LIST[str_index] = buff;
				SCANNER_RESULT[res_index] = 2000 + str_index;
				str_index++;
				res_index++;
				buff = "";
				p++;
				continue;
			}

			// read numbers integer or real
			if (buff.length() == 0 && checkNumber(input.charAt(p))) {
				while (p < size && checkNumber(input.charAt(p))) {
					buff += input.charAt(p);
					p++;

				}
				if (p == size || input.charAt(p) != '.') {// integer
					SCANNER_INTEGER_LIST[int_index] = Integer.valueOf(buff);
					buff = "";
					SCANNER_RESULT[res_index] = 3000 + int_index;
					int_index++;
					res_index++;
				} else if (p < size) {// real
					buff += '.';
					p++;
					while (p < size && checkNumber(input.charAt(p))) {
						buff += input.charAt(p);
						p++;
					}
					SCANNER_REAL_LIST[rea_index] = Double.valueOf(buff);
					SCANNER_RESULT[res_index] = 4000 + rea_index;
					rea_index++;
					res_index++;
					buff = "";

				}
				continue;
			}

			// space \t \n
			if (input.charAt(p) == ' ' || input.charAt(p) == '\n'
					|| input.charAt(p) == '\t') {
				if (buff.length() != 0) {
					check(buff);
					buff = "";
				}
				p++;
				continue;
			}

			// ,
			if (input.charAt(p) == ',') {

				if (buff.length() != 0) {
					check(buff);
					buff = "";
				}
				SCANNER_RESULT[res_index] = 1000;
				res_index++;
				p++;
				continue;
			}

			// ;

			if (input.charAt(p) == ';') {
				if (buff.length() != 0) {
					check(buff);
					buff = "";

				}
				SCANNER_RESULT[res_index] = 1001;
				res_index++;
				p++;
				continue;
			}

			// (
			if (input.charAt(p) == '(') {
				if (buff.length() != 0) {
					check(buff);
					buff = "";

				}
				SCANNER_RESULT[res_index] = 1004;
				res_index++;
				p++;
				continue;
			}

			// )
			if (input.charAt(p) == ')') {
				if (buff.length() != 0) {
					check(buff);
					buff = "";

				}
				SCANNER_RESULT[res_index] = 1005;
				res_index++;
				p++;
				continue;
			}

			// =
			if (input.charAt(p) == '=') {
				if (buff.length() != 0) {
					check(buff);
					buff = "";

				}
				SCANNER_RESULT[res_index] = 1006;
				res_index++;
				p++;
				continue;
			}

			// >
			if (input.charAt(p) == '>') {
				if (buff.length() != 0) {
					check(buff);
					buff = "";

				}
				SCANNER_RESULT[res_index] = 1007;
				res_index++;
				p++;
				continue;
			}

			// <
			if (input.charAt(p) == '<') {
				if (buff.length() != 0) {
					check(buff);
					buff = "";

				}
				SCANNER_RESULT[res_index] = 1008;
				res_index++;
				p++;
				continue;
			}

			// *
			if (input.charAt(p) == '*') {
				if (buff.length() != 0) {
					check(buff);
					buff = "";

				}
				SCANNER_RESULT[res_index] = 1009;
				res_index++;
				p++;
				continue;
			}

			buff += input.charAt(p);
			p++;
		}

		if (buff.length() != 0)
			check(buff);
		
		
		Parser.start();
		return SCANNER_RESULT;
	}

	/**
	 * check whether this char is a number
	 * 
	 * @param c
	 *            the input char
	 * @return true if it is;false otherwise
	 */
	private static boolean checkNumber(char c) {
		switch (c) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			return true;
		default:
			return false;
		}
	}

	/**
	 * add a new identifier
	 * 
	 * @param buff
	 *            the string buff
	 */
	private static void check(String buff) {

		// * 1100 CREATE
		if (buff.compareTo("CREATE") == 0) {
			SCANNER_RESULT[res_index] = 1100;
			res_index++;
			return;
		}
		// * 1101 DATABASE
		if (buff.compareTo("DATABASE") == 0) {
			SCANNER_RESULT[res_index] = 1101;
			res_index++;
			return;
		}
		// * 1102 TABLE
		if (buff.compareTo("TABLE") == 0) {
			SCANNER_RESULT[res_index] = 1102;
			res_index++;
			return;
		}
		// * 1103 INSERT
		if (buff.compareTo("INSERT") == 0) {
			SCANNER_RESULT[res_index] = 1103;
			res_index++;
			return;
		}
		// * 1104 DELETE
		if (buff.compareTo("DELETE") == 0) {
			SCANNER_RESULT[res_index] = 1104;
			res_index++;
			return;
		}
		// * 1105 INTO
		if (buff.compareTo("INTO") == 0) {
			SCANNER_RESULT[res_index] = 1105;
			res_index++;
			return;
		}
		// * 1106 VALUES
		if (buff.compareTo("VALUES") == 0) {
			SCANNER_RESULT[res_index] = 1106;
			res_index++;
			return;
		}
		// * 1107 SET
		if (buff.compareTo("SET") == 0) {
			SCANNER_RESULT[res_index] = 1107;
			res_index++;
			return;
		}
		// * 1108 SELECT
		if (buff.compareTo("SELECT") == 0) {
			SCANNER_RESULT[res_index] = 1108;
			res_index++;
			return;
		}
		// * 1109 FROM
		if (buff.compareTo("FROM") == 0) {
			SCANNER_RESULT[res_index] = 1109;
			res_index++;
			return;
		}
		// * 1110 WHERE
		if (buff.compareTo("WHERE") == 0) {
			SCANNER_RESULT[res_index] = 1110;
			res_index++;
			return;
		}
		// * 1111 AND
		if (buff.compareTo("AND") == 0) {
			SCANNER_RESULT[res_index] = 1111;
			res_index++;
			return;
		}
		// * 1112 OR
		if (buff.compareTo("OR") == 0) {
			SCANNER_RESULT[res_index] = 1112;
			res_index++;
			return;
		}
		// * 1113 NULL
		if (buff.compareTo("NULL") == 0) {
			SCANNER_RESULT[res_index] = 1113;
			res_index++;
			return;
		}
		// * 1114 NOT
		if (buff.compareTo("NOT") == 0) {
			SCANNER_RESULT[res_index] = 1114;
			res_index++;
			return;
		}
		// * 1115 ALL
		if (buff.compareTo("ALL") == 0) {
			SCANNER_RESULT[res_index] = 1115;
			res_index++;
			return;
		}
		// * 1116 DISTINCT
		if (buff.compareTo("DISTINCT") == 0) {
			SCANNER_RESULT[res_index] = 1116;
			res_index++;
			return;
		}
		// * 1117 UNION
		if (buff.compareTo("UNION") == 0) {
			SCANNER_RESULT[res_index] = 1117;
			res_index++;
			return;
		}
		// * 1118 AS
		if (buff.compareTo("AS") == 0) {
			SCANNER_RESULT[res_index] = 1118;
			res_index++;
			return;
		}
		// * 1119 ORDER
		if (buff.compareTo("ORDER") == 0) {
			SCANNER_RESULT[res_index] = 1119;
			res_index++;
			return;
		}
		// * 1120 BY
		if (buff.compareTo("BY") == 0) {
			SCANNER_RESULT[res_index] = 1120;
			res_index++;
			return;
		}
		// * 1121 GROUP
		if (buff.compareTo("GROUP") == 0) {
			SCANNER_RESULT[res_index] = 1121;
			res_index++;
			return;
		}
		// * 1122 USE
		if (buff.compareTo("USE") == 0) {
			SCANNER_RESULT[res_index] = 1122;
			res_index++;
			return;
		}
		
		// * 1200 INTEGER
		if (buff.compareTo("INTEGER") == 0) {
			SCANNER_RESULT[res_index] = 1200;
			res_index++;
			return;
		}
		
		// * 1201 REAL
		if (buff.compareTo("REAL") == 0) {
			SCANNER_RESULT[res_index] = 1201;
			res_index++;
			return;
		}
		
		// * 1202 STRING
		if (buff.compareTo("STRING") == 0) {
			SCANNER_RESULT[res_index] = 1202;
			res_index++;
			return;
		}
		
		

		SCANNER_IDENTIFIER_LIST[ide_index] = buff;
		SCANNER_RESULT[res_index] = 5000 + ide_index;
		ide_index++;
		res_index++;
	}
	/**
	 * output syntax error
	 */
	private static void perror() {
		Functions.output("Syntax error!");
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String input = "SELECT ABC FROM COM WHERE A=1;";
		int[] result = scan(input);
		int i = 0;
		System.out.println("result:");
		while (result[i] != 0) {
			System.out.print(result[i] + " ");
			i++;
		}
		System.out.println();

		System.out.println("identifier");
		for (i = 0; i < ide_index; i++) {
			System.out.print(SCANNER_IDENTIFIER_LIST[i] + " ");
		}
		System.out.println();

		System.out.println("string");
		for (i = 0; i < str_index; i++) {
			System.out.print(SCANNER_STRING_LIST[i] + " ");
		}
		System.out.println();

		System.out.println("integer");
		for (i = 0; i < int_index; i++) {
			System.out.print(SCANNER_INTEGER_LIST[i] + " ");
		}
		System.out.println();

		System.out.println("real");
		for (i = 0; i < rea_index; i++) {
			System.out.print(SCANNER_REAL_LIST[i] + " ");
		}
		System.out.println();

		System.out.println(input);

	}

}
